package com.eastfair.auth.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.annotation.annotation.cache.Cache;
import com.eastfair.annotation.annotation.cache.Magic;
import com.eastfair.auth.dao.BusinessMapper;
import com.eastfair.auth.dao.RoleMapper;
import com.eastfair.auth.dto.OrganizationDTO;
import com.eastfair.auth.dto.RoleDTO;
import com.eastfair.auth.entity.MenuRole;
import com.eastfair.auth.entity.Role;
import com.eastfair.auth.enumeration.OrganizationOrgTypeEnum;
import com.eastfair.auth.enumeration.RoleRoleTypeEnum;
import com.eastfair.auth.exceptioncode.AuthServiceExceptionCode;
import com.eastfair.auth.service.*;
import com.eastfair.auth.util.DataIsoLotionUtil;
import com.eastfair.auth.vo.RoleVo;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.auth.RoleCacheKeyBuilder;
import com.eastfair.cache.repository.CacheOps;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.exception.NoBackBizException;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.model.DataIsolationVo;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;

import com.eastfair.projectcore.dto.MenuDTO;
import com.eastfair.projectcore.entity.ProjectDb;
import com.eastfair.projectcore.vo.MenuVO;
import com.eastfair.uid.baidu.rule.SnowFlakeRole;
import com.eastfair.util.CodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.management.relation.RoleList;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.stream.Collectors;

import static com.eastfair.core.base.R.SUCCESS_CODE;

/**
 * <p>
 * 业务实现类
 *
 * </p>
 *
 * @author ligang
 * @date 2021-07-23
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class RoleServiceImpl extends SuperCacheServiceImpl<RoleMapper, Role> implements RoleService {
    @Autowired
    protected CacheOps cacheOps;

    @Autowired
    ProjectCoreServiceFeign projectCoreServiceFeign;

    @Autowired
    MenuRoleService menuRoleService;

    @Autowired
    OrganizationRoleService organizationRoleService;

    @Autowired
    BusinessMapper businessMapper;

    @Autowired
    SnowFlakeRole snowFlakeRole;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<Role> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(Role model) {
        model.setId(snowFlakeRole.findUidSimple());
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        model.setTeamId(ContextUtil.getTeamId());
        //code 码
        if (StringUtils.isBlank(model.getCode())) {
            model.setCode(queryCode(model));
        }
        return R.successDef();
    }

    public String queryCode(Role model) {
        String code = nonredundantCode();
        return code;
    }

    /**
     * 获取不重复的code
     *
     * @return
     */
    public String nonredundantCode() {
        String code = CodeUtils.randomCode(6);
        //是否重复
        int num = queryCodeSize(code);
        if (num > 0) {
            nonredundantCode();
        }
        return code;
    }

    public int queryCodeSize(String code) {
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(code)) {
            queryWrapper.lambda().eq(Role::getCode, code);
        }
        queryWrapper.lambda().eq(Role::getIsDeleted, BusinessConstant.DELETE_NO);
        return count(queryWrapper);
    }


    @Override
    public CacheKeyBuilder getCacheKeyBuilder() {
        return new RoleCacheKeyBuilder();
    }

    @Override
    public R<Role> createRole(RoleDTO roleDTO) {
        Role role = new Role();
        BeanUtils.copyProperties(roleDTO, role);
        //判断业务标识是否重复
        if (StringUtils.isNotBlank(roleDTO.getBusinessTag()) && !"others".equals(roleDTO.getBusinessTag().toLowerCase()) && !"role_other".equals(roleDTO.getBusinessTag().toLowerCase())) {
            Role role1 = new Role();
            role1.setBusinessTag(roleDTO.getBusinessTag());
            role1.setSubsystemId(ContextUtil.getSubSystemId());
            List<Role> roleList = list(role1, null, null);
            if (roleList != null && !roleList.isEmpty()) {
                throw NoBackBizException.wrap(AuthServiceExceptionCode.ROLE_AGAIN);
//                return R.fail("角色业务标识已经存在");
            }
        }
        save(role);
        roleDTO.setId(role.getId());
        reloadRoleRelationOfMenu(roleDTO);
        return R.success(role);
    }

    @Override
    public R<Role> createRoleOfRepetition(RoleDTO roleDTO) {
        Role role = new Role();

        log.info("createRoleOfRepetition is execute roleDTO is {}", JSONObject.toJSONString(roleDTO));

        log.info("teamid is {}", ContextUtil.getTeamId());
        Role updateRole = null;
        BeanUtils.copyProperties(roleDTO, role);
        //判断业务标识是否重复
        if (StringUtils.isNotBlank(roleDTO.getBusinessTag()) && !"others".equals(roleDTO.getBusinessTag().toLowerCase()) && !"role_other".equals(roleDTO.getBusinessTag().toLowerCase())) {
            Role role1 = new Role();
            role1.setBusinessTag(roleDTO.getBusinessTag());
            role1.setSubsystemId(ContextUtil.getSubSystemId());
            List<Role> roleList = list(role1, null, null);
            log.info("createRoleOfRepetition roleList is {}", JSONObject.toJSONString(roleList));
            if (roleList != null && !roleList.isEmpty()) {
                updateRole = roleList.get(0);
            }
        }
        if (updateRole != null) {
            log.info("createRoleOfRepetition is execute updateRole is {}", JSONObject.toJSONString(updateRole));
            role = updateRole;
        } else {
            log.info("createRoleOfRepetition is execute role is {}", JSONObject.toJSONString(updateRole));
            save(role);
            roleDTO.setId(role.getId());
            reloadRoleRelationOfMenu(roleDTO);
        }
        return R.success(role);
    }

    @Override
    public R<Role> updateRole(RoleDTO roleDTO) {
        Role role = new Role();
        BeanUtils.copyProperties(roleDTO, role);
        updateById(role);
        reloadRoleRelationOfMenu(roleDTO);
        return R.success(role);
    }

    @Override
    public R delRole(List<Long> roleIds) {
        //删除角色，并删除角色下的菜单关系和组织关系
        if (roleIds == null || roleIds.isEmpty()) {
            return R.success();
        }
        //剔除角色关系
        removeRoleRelation(roleIds);
        //删除角色
        for (Long roleId : roleIds) {
            Role role = getByIdCache(roleId);
            if (role != null) {
                role.setIsDeleted(BusinessConstant.DELETE_YES);
                updateById(role);
            }
        }
        return R.success();
    }

    @Override
    public R removeRoleRelation(List<Long> roleIds) {
        //删除组织关系
        return organizationRoleService.removeOfRole(roleIds);
    }

    @Override
    public R removeRoleRelationOfMenu(List<Long> roleIds) {
        //删除菜单关系
        return menuRoleService.removeRole(roleIds);
    }

    @Override
    public R reloadRoleRelationOfMenu(RoleDTO roleDTO) {
        //剔除关系
        removeRoleRelationOfMenu(Arrays.asList(roleDTO.getId()));
        //重新添加关系
        menuRoleService.addOfMenu(roleDTO.getId(), roleDTO.getMenuIds());

        return R.success();
    }

    @Override
    public R reloadRoleRelationOfSubSystem(RoleDTO roleDTO) {
        List<Role> roleList = businessMapper.listRole(roleDTO);
        if (CollectionUtil.isNotEmpty(roleList)) {
            //并发
            ExecutorService executorService = Executors.newCachedThreadPool();
            List<FutureTask> futureTaskList = new ArrayList<>();

            for (Role role : roleList) {
                futureTaskList.add((FutureTask) executorService.submit(() -> {
                    RoleDTO roleDTO1 = new RoleDTO();
                    roleDTO1.setId(role.getId());
                    roleDTO1.setMenuIds(roleDTO.getMenuIds());
                    reloadRoleRelationOfMenu(roleDTO1);
                }));
            }
//            futureTaskList.forEach(s -> {
//                try {
//                    s.get();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                } catch (ExecutionException e) {
//                    e.printStackTrace();
//                }
//            });


        }
        return null;
    }

    @Override
    public List<RoleVo> findAllById(List<Long> roleIds) {
        return doToVos(list(null, null, roleIds));
    }

    @Override
    public List<RoleVo> findAllMenuById(List<Long> roleIds) {
        //角色信息
        List<RoleVo> roleVoList = new ArrayList<>();
        //角色和菜单的关系表
        R<List<MenuRole>> r = menuRoleService.findOfRole(roleIds);
        if (SUCCESS_CODE == r.getCode()) {
            List<MenuRole> menuRoleList = r.getData();
            //根据角色分组
            Map<Long, List<MenuRole>> roleGroupList = menuRoleList.stream().collect(Collectors.groupingBy(MenuRole::getRoleId));
            for (Long roleId : roleGroupList.keySet()) {
                List<MenuRole> menuRoleList1 = roleGroupList.get(roleId);
                if (menuRoleList1 != null && !menuRoleList1.isEmpty()) {
                    //查询角色下的菜单
                    MenuDTO menuDTO = new MenuDTO();
                    menuDTO.setMenuIds(menuRoleList1.stream().map(MenuRole::getMenuId).collect(Collectors.toList()));
                    R<List<MenuVO>> menuVoList = projectCoreServiceFeign.findAllByChildId(menuDTO);
                    if (SUCCESS_CODE == menuVoList.getCode()) {
                        RoleVo roleVo = new RoleVo();
                        Role role = getByIdCache(roleId);
                        BeanUtils.copyProperties(role, roleVo);
                        roleVo.setMenuVOList(menuVoList.getData());
                        roleVo.setMenuIds(menuRoleList1.stream().map(MenuRole::getMenuId).collect(Collectors.toList()));
                        roleVoList.add(roleVo);
                    }
                }
            }
        }
        return roleVoList;
    }

    @Override
    public List<Long> findMenuIdById(Long roleId) {
        //角色信息
        List<RoleVo> roleVoList = new ArrayList<>();
        //角色和菜单的关系表
        R<List<MenuRole>> r = menuRoleService.findOfRole(Arrays.asList(roleId));
        if (SUCCESS_CODE == r.getCode()) {
            List<MenuRole> menuRoleList = r.getData();
            return menuRoleList.stream().map(MenuRole::getMenuId).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public RoleVo getAllById(Long roleId) {
        Role role = getByIdCache(roleId);
        if (role == null) {
            return null;
        }
        RoleVo roleVo = doToVo(role);
        //查询菜单集合
        List<Long> menuIds = findMenuIdById(roleId);
        if (menuIds != null && !menuIds.isEmpty()) {
            R<List<Long>> listR = projectCoreServiceFeign.queryBestChildMenuId(menuIds);
            if (SUCCESS_CODE == listR.getCode()) {
                roleVo.setMenuIds(listR.getData());
            }
        }
        return roleVo;
    }

    @Override
    public List<RoleVo> queryAllRole() {
        return doToVos(list(null, null, null));
    }

    @Override
    public List<Role> initRole(OrganizationDTO organizationDTO) {
        List<Role> result = new ArrayList<>();
        for (RoleRoleTypeEnum roleRoleTypeEnum : RoleRoleTypeEnum.values()) {
            if (roleRoleTypeEnum.getCode().lastIndexOf("_ADMIN") < 0) {
                continue;
            }
            //是否包含系统
            if (DataIsoLotionUtil.findSubSystemId(organizationDTO.getSubsystemList(), roleRoleTypeEnum.getCode().substring(0, roleRoleTypeEnum.getCode().lastIndexOf("_ADMIN"))) == null) {
                continue;
            }
//            ContextUtil.setSubSystemId(DataIsoLotionUtil.findSubSystemId(organizationDTO.getSubsystemList(), roleRoleTypeEnum.getCode().substring(0, roleRoleTypeEnum.getCode().lastIndexOf("_ADMIN"))));
            if (ContextUtil.getSubSystemId() == null) {
                continue;
            }
            Role role = new Role();
            role.setName(roleRoleTypeEnum.getDesc());
            role.setRoleType(roleRoleTypeEnum);
            QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(Role::getRoleType, roleRoleTypeEnum);
            queryWrapper.lambda().eq(Role::getIsDeleted, BusinessConstant.DELETE_NO);
            Role updRole = getOne(queryWrapper);
            if (updRole != null) {
                updRole.setName(roleRoleTypeEnum.getDesc());
                updRole.setRoleType(roleRoleTypeEnum);
                updateById(updRole);
                result.add(updRole);
            } else {
                save(role);
                result.add(role);
            }
        }

//        for (Role role : result) {
//            //默认系统管理员角色占所有菜单，后续页面修改
//            R<List<Long>> listR = projectCoreServiceFeign.queryAllMenuId();
//            if (SUCCESS_CODE == listR.getCode() && listR.getData() != null && !listR.getData().isEmpty()) {
//                //角色加入到组织
//                RoleDTO roleDTO = new RoleDTO();
//                roleDTO.setId(role.getId());
//                roleDTO.setMenuIds(listR.getData());
//                reloadRoleRelationOfMenu(roleDTO);
//            }
//        }


        return result;
    }

    @Override
    public List<Role> list(Role role, List<Long> orgIds, List<Long> ids) {
        if (role == null) {
            role = new Role();
        }
        if (role.getIsEnabled() == null) {
            role.setIsEnabled(BusinessConstant.ENABLE_YES);
        }


        return ((RoleService) AopContext.currentProxy()).listOfCache(role, orgIds, ids);
    }

    @Override
//    @Cache( key = "#hash(#args)")
    @Cache(key = "",
            magic = @Magic(
                    key = "{{'id', #args[0]?.id},{'roleType', #args[0]?.roleType}," +
                            "{'name', #args[0]?.name},{'code', #args[0]?.code},{'businessTag', #args[0]?.businessTag}," +
                            "{'id', #args[2]}}"))
    public List<Role> listOfCache(Role role, List<Long> orgIds, List<Long> ids) {
        //查询
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        if (role != null) {
            if (role.getRoleType() != null) {
                queryWrapper.lambda().eq(Role::getRoleType, role.getRoleType());
            }
            if (role.getName() != null) {
                queryWrapper.lambda().like(Role::getName, "%" + role.getName() + "%");
            }
            if (role.getCode() != null) {
                queryWrapper.lambda().eq(Role::getCode, role.getCode());
            }

            if (role.getId() != null) {
                queryWrapper.lambda().eq(Role::getId, role.getId());
            }
            if (StringUtils.isNotBlank(role.getBusinessTag())) {
                queryWrapper.lambda().eq(Role::getBusinessTag, role.getBusinessTag());
            }
            if (role.getIsEnabled()!=null) {
                queryWrapper.lambda().eq(Role::getIsEnabled, role.getIsEnabled());
            }
        }
        if (ids != null && !ids.isEmpty()) {
            queryWrapper.lambda().in(Role::getId, ids);
        }
//        queryWrapper.lambda().eq(Role::getIsEnabled, BusinessConstant.ENABLE_YES);
        queryWrapper.lambda().eq(Role::getIsDeleted, BusinessConstant.DELETE_NO);
        List<Role> roleList = list(queryWrapper);
        return roleList;
    }

    @Override
    public RoleVo doToVo(Role role) {
        if(role ==null){
            return null;
        }
        RoleVo roleVo = new RoleVo();
        BeanUtils.copyProperties(role, roleVo);
        roleVo.setId(role.getId());
        return roleVo;
    }

    @Override
    public List<RoleVo> doToVos(List<Role> roleList) {
        if (roleList == null || roleList.isEmpty()) {
            return null;
        }
        List<RoleVo> result = new ArrayList<>();
        for (Role role : roleList) {
            result.add(doToVo(role));
        }
        return result;
    }
}
